package com.fcscs.cservice.ws.endpoint;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;

import com.fcscs.core.common.MainEnums;
import com.fcscs.core.util.CommonUtil;
import com.fcscs.cservice.common.CServiceCommonEnums.ExpressCheckoutType;
import com.fcscs.cservice.domain.model.BillingView;
import com.fcscs.cservice.domain.model.FolioView;
import com.fcscs.cservice.domain.model.GuestProfileView;
import com.fcscs.cservice.domain.model.MessageIdAndStatus;
import com.fcscs.cservice.domain.model.MessageView;
import com.fcscs.cservice.domain.model.RCView;
import com.fcscs.cservice.domain.model.RateView;
import com.fcscs.cservice.domain.model.ReservationView;
import com.fcscs.cservice.service.ReservationManager;
import com.fcscs.cservice.ws.WebServiceUtils;
import com.fcscs.cservice.ws.schema.reservationservice.AdvanceFindReservationsRequest;
import com.fcscs.cservice.ws.schema.reservationservice.AdvanceFindReservationsResponse;
import com.fcscs.cservice.ws.schema.reservationservice.ExpressCheckOutRequest;
import com.fcscs.cservice.ws.schema.reservationservice.ExpressCheckOutResponse;
import com.fcscs.cservice.ws.schema.reservationservice.FindReservationsRequest;
import com.fcscs.cservice.ws.schema.reservationservice.FindReservationsResponse;
import com.fcscs.cservice.ws.schema.reservationservice.GetFolioRequest;
import com.fcscs.cservice.ws.schema.reservationservice.GetFolioResponse;
import com.fcscs.cservice.ws.schema.reservationservice.GetMessagesRequest;
import com.fcscs.cservice.ws.schema.reservationservice.GetMessagesResponse;
import com.fcscs.cservice.ws.schema.reservationservice.GetRCRequest;
import com.fcscs.cservice.ws.schema.reservationservice.GetRCResponse;
import com.fcscs.cservice.ws.schema.reservationservice.GetReservationRequest;
import com.fcscs.cservice.ws.schema.reservationservice.GetReservationResponse;
import com.fcscs.cservice.ws.schema.reservationservice.SendEFolioRequest;
import com.fcscs.cservice.ws.schema.reservationservice.SendEFolioResponse;
import com.fcscs.cservice.ws.schema.reservationservice.UpdateMessagesRequest;
import com.fcscs.cservice.ws.schema.reservationservice.UpdateMessagesResponse;
import com.fcscs.cservice.ws.schema.reservationservice.UpdateRCRequest;
import com.fcscs.cservice.ws.schema.reservationservice.UpdateRCResponse;
import com.fcscs.share.util.TimezoneUtils;

@Endpoint
public class ReservationServiceEndpoint {

	@Autowired
	ReservationManager resvMgr;

	@PayloadRoot(localPart = CServiceWSConstants.FIND_RESV_REQ, namespace = CServiceWSConstants.RESV_SERVICE_NAMESPACE_URI)
	@ResponsePayload
	public FindReservationsResponse findResvs(@RequestPayload FindReservationsRequest req) {
		FindReservationsResponse resp = new FindReservationsResponse();

		Calendar st = Calendar.getInstance();
		st.setTime(TimezoneUtils.setDateStartTime(req.getDate()));
		Calendar ed = Calendar.getInstance();
		ed.setTime(TimezoneUtils.setDateEndTime(req.getDate()));

		MainEnums.TimeZone tz = TimezoneUtils.getTimezone(CommonUtil.getWsSessionPropertyId());
		Date stDt = TimezoneUtils.convertToServerTimeZone(st.getTime(), tz);
		Date edDt = TimezoneUtils.convertToServerTimeZone(ed.getTime(), tz);

		List<ReservationView> rvs = resvMgr.findReservations(CommonUtil.getWsSessionPropertyId(), req.getTerm(),
				req.getResrvStatusId(), stDt, edDt, req.getStart(), req.getNumResults());

		int cnt = resvMgr.findReservationsCnt(CommonUtil.getWsSessionPropertyId(), req.getTerm(),
				req.getResrvStatusId(), stDt, edDt);

		convRsvViewToLocalTime(rvs, tz);
		resp.setReservationList(rvs);
		resp.setTotalCnt(cnt);

		return resp;
	}

	@PayloadRoot(localPart = "GetFolioRequest", namespace = CServiceWSConstants.RESV_SERVICE_NAMESPACE_URI)
	@ResponsePayload
	public GetFolioResponse getFolio(@RequestPayload GetFolioRequest req) {

		GetFolioResponse resp = new GetFolioResponse();
		FolioView folio = resvMgr.getFolioView(req.getFolioId());
		MainEnums.TimeZone tz = TimezoneUtils.getTimezone(CommonUtil.getWsSessionPropertyId());
		convFolioViewToLocalTime(folio, tz);
		resp.setFolioView(folio);
		return resp;
	}

	@PayloadRoot(localPart = "ExpressCheckOutRequest", namespace = CServiceWSConstants.RESV_SERVICE_NAMESPACE_URI)
	@ResponsePayload
	public ExpressCheckOutResponse expressCheckout(@RequestPayload ExpressCheckOutRequest req) {
		ExpressCheckOutResponse resp = new ExpressCheckOutResponse();
		Boolean isAuto = null;
		if (ExpressCheckoutType.AUTO.toString().equals(req.getCheckoutType())) {
			isAuto = true;
		} else if (ExpressCheckoutType.MANU.toString().equals(req.getCheckoutType())) {
			isAuto = false;
		}
		if (isAuto == null) {
			resp.setSuccess(false);
		} else {
			String sign = req.getSignatureFile();
			byte[] bloc = WebServiceUtils.convertToByteArray(sign);
			boolean res = resvMgr.checkOut(isAuto, req.getFolioId(), bloc, req.getPaymentMethodId(), req.getRemarks());
			resp.setSuccess(res);
		}		
		return resp;
	}

	@PayloadRoot(localPart = "GetMessagesRequest", namespace = CServiceWSConstants.RESV_SERVICE_NAMESPACE_URI)
	@ResponsePayload
	public GetMessagesResponse getMessages(@RequestPayload GetMessagesRequest req) {

		GetMessagesResponse resp = new GetMessagesResponse();
		List<MessageView> msgs = resvMgr.getMessages(req.getReservationId());
		MainEnums.TimeZone tz = TimezoneUtils.getTimezone(CommonUtil.getWsSessionPropertyId());
		convMsgViewToLocalTime(msgs, tz);
		resp.setMessageList(msgs);
		return resp;
	}

	@PayloadRoot(localPart = "UpdateMessagesRequest", namespace = CServiceWSConstants.RESV_SERVICE_NAMESPACE_URI)
	@ResponsePayload
	public UpdateMessagesResponse updateMessages(@RequestPayload UpdateMessagesRequest req) {

		UpdateMessagesResponse resp = new UpdateMessagesResponse();
		List<MessageIdAndStatus> msgs = resvMgr.updateMessages(req.getMessageList());
		resp.setMessageList(msgs);
		return resp;
	}

	@PayloadRoot(localPart = CServiceWSConstants.AFIND_RESV_REQ, namespace = CServiceWSConstants.RESV_SERVICE_NAMESPACE_URI)
	@ResponsePayload
	public AdvanceFindReservationsResponse advanceFindResvs(@RequestPayload AdvanceFindReservationsRequest req) {
		AdvanceFindReservationsResponse resp = new AdvanceFindReservationsResponse();
		Date stDt = null;
		Date edDt = null;

		MainEnums.TimeZone tz = TimezoneUtils.getTimezone(CommonUtil.getWsSessionPropertyId());
		if (req.getArrivalDate() == null && req.getDepartDate() == null) {
			Date dt = new Date();
			Calendar st = Calendar.getInstance();
			st.setTime(TimezoneUtils.setDateStartTime(dt));
			Calendar ed = Calendar.getInstance();
			ed.setTime(TimezoneUtils.setDateEndTime(dt));

			stDt = TimezoneUtils.convertToServerTimeZone(st.getTime(), tz);
			edDt = TimezoneUtils.convertToServerTimeZone(ed.getTime(), tz);
		} else {
			req.setArrivalDate(resetFindDate(req.getArrivalDate(), req.getEta()));
			req.setDepartDate(resetFindDate(req.getDepartDate(), req.getEtd()));
		}

		List<ReservationView> rvs = resvMgr.findReservations(CommonUtil.getWsSessionPropertyId(), req.getFirstname(),
				req.getLastname(), req.getResrvStatusId(), req.getRoomNo(), req.getMembershipNo(),
				req.getRoomStatusId(), req.getBaggageNo(), TimezoneUtils.convertToServerTimeZone(req.getArrivalDate(), tz),
				TimezoneUtils.convertToServerTimeZone(req.getDepartDate(), tz), TimezoneUtils.convertToServerTimeZone(req.getEta(), tz),
				TimezoneUtils.convertToServerTimeZone(req.getEtd(), tz), stDt, edDt, req.getStart(), req.getNumResults());

		int cnt = resvMgr.findReservationsCnt(CommonUtil.getWsSessionPropertyId(), req.getFirstname(),
				req.getLastname(), req.getResrvStatusId(), req.getRoomNo(), req.getMembershipNo(),
				req.getRoomStatusId(), req.getBaggageNo(), TimezoneUtils.convertToServerTimeZone(req.getArrivalDate(), tz),
				TimezoneUtils.convertToServerTimeZone(req.getDepartDate(), tz), TimezoneUtils.convertToServerTimeZone(req.getEta(), tz),
				TimezoneUtils.convertToServerTimeZone(req.getEtd(), tz), stDt, edDt);

		convRsvViewToLocalTime(rvs, tz);
		resp.setReservationViewList(rvs);
		resp.setTotalCnt(cnt);

		return resp;
	}

	private static Date resetFindDate(Date date, Date time) {
		if (date != null) {
			Calendar c = Calendar.getInstance();
			c.setTime(date);
			if (time == null) {
				c.set(Calendar.HOUR_OF_DAY, 0);
				c.set(Calendar.MINUTE, 0);
				c.set(Calendar.SECOND, 0);
				date = c.getTime();
			} else {
				Calendar tc = Calendar.getInstance();
				tc.setTime(time);
				c.set(Calendar.HOUR_OF_DAY, tc.get(Calendar.HOUR_OF_DAY));
				c.set(Calendar.MINUTE, tc.get(Calendar.MINUTE));
				c.set(Calendar.SECOND, 0);
				date = c.getTime();
			}
		}
		return date;
	}

	@PayloadRoot(localPart = CServiceWSConstants.GET_RESV_REQ, namespace = CServiceWSConstants.RESV_SERVICE_NAMESPACE_URI)
	@ResponsePayload
	public GetReservationResponse getFindResv(@RequestPayload GetReservationRequest req) {
		GetReservationResponse resp = new GetReservationResponse();

		ReservationView rv = resvMgr.getReservationView(req.getReservationId());
		MainEnums.TimeZone tz = TimezoneUtils.getTimezone(CommonUtil.getWsSessionPropertyId());
		convRsvViewToLocalTime(rv, tz);
		resp.setReservationView(rv);
		return resp;
	}

	@PayloadRoot(localPart = CServiceWSConstants.GET_RC_REQ, namespace = CServiceWSConstants.RESV_SERVICE_NAMESPACE_URI)
	@ResponsePayload
	public GetRCResponse getFindRC(@RequestPayload GetRCRequest req) {
		GetRCResponse resp = new GetRCResponse();

		RCView rv = resvMgr.getRCView(req.getRcId(), CommonUtil.getWsSessionUsername());
		MainEnums.TimeZone tz = TimezoneUtils.getTimezone(CommonUtil.getWsSessionPropertyId());
		convRCViewToLocalTime(rv, tz);
		resp.setRcView(rv);
		return resp;
	}

	@PayloadRoot(localPart = CServiceWSConstants.UPDATE_RC_REQ, namespace = CServiceWSConstants.RESV_SERVICE_NAMESPACE_URI)
	@ResponsePayload
	public UpdateRCResponse updateRC(@RequestPayload UpdateRCRequest req) {
		UpdateRCResponse resp = new UpdateRCResponse();
		RCView rv = req.getRcView();
		rv.setUpdated(new Date());
		rv.setOrgId(CommonUtil.getWsSessionOrgId());
		rv.setPropertyId(CommonUtil.getWsSessionPropertyId());
		byte[] initial = WebServiceUtils.convertToByteArray(req.getInitialFile());
		byte[] sign = WebServiceUtils.convertToByteArray(req.getSignatureFile());
		MainEnums.TimeZone tz = TimezoneUtils.getTimezone(CommonUtil.getWsSessionPropertyId());
		convRCViewToServerTime(rv, tz);
		rv = resvMgr.updateRCView(rv, initial, sign);
		convRCViewToLocalTime(rv, tz);
		resp.setRCView(rv);
		resp.setSuccess(true);
		return resp;
	}

	@PayloadRoot(localPart = CServiceWSConstants.SEND_EFOLIO_REQ, namespace = CServiceWSConstants.RESV_SERVICE_NAMESPACE_URI)
	@ResponsePayload
	public SendEFolioResponse sendEFolio(@RequestPayload SendEFolioRequest req) {
		SendEFolioResponse resp = new SendEFolioResponse();
		boolean res = resvMgr.sendEFolio(req.getReservationId(), req.getFolioId());
		resp.setSuccess(res);
		return resp;
	}

	private static void convRsvViewToLocalTime(List<ReservationView> rvs, MainEnums.TimeZone tz) {
		if (rvs == null) {
			return;
		}
		for (ReservationView rv : rvs) {
			convRsvViewToLocalTime(rv, tz);
		}
	}

	private static void convRsvViewToLocalTime(ReservationView rv, MainEnums.TimeZone tz) {
		if (rv == null) {
			return;
		}
		rv.setArrivalDateTime(TimezoneUtils.convertToLocalTimeZone(rv.getArrivalDateTime(), tz));
		rv.setDepartureDateTime(TimezoneUtils.convertToLocalTimeZone(rv.getDepartureDateTime(), tz));
		rv.setArrivalFlightDate(TimezoneUtils.convertToLocalTimeZone(rv.getArrivalFlightDate(), tz));
		rv.setDepartureFlightDate(TimezoneUtils.convertToLocalTimeZone(rv.getDepartureFlightDate(), tz));
		rv.setCreated(TimezoneUtils.convertToLocalTimeZone(rv.getCreated(), tz));
		rv.setUpdated(TimezoneUtils.convertToLocalTimeZone(rv.getUpdated(), tz));
		List<ReservationView.RC> rcs = rv.getRcs();
		if (rcs != null) {
			for (ReservationView.RC rc : rcs) {
				rc.setDate(TimezoneUtils.convertToLocalTimeZone(rc.getDate(), tz));
			}
		}
	}

	private void convRCViewToLocalTime(RCView rv, MainEnums.TimeZone tz) {
		if (rv == null) {
			return;
		}
		rv.setGuestSignatureDateTime(TimezoneUtils.convertToLocalTimeZone(rv.getGuestSignatureDateTime(), tz));
		rv.setArrivalDateTime(TimezoneUtils.convertToLocalTimeZone(rv.getArrivalDateTime(), tz));
		rv.setDepartureDateTime(TimezoneUtils.convertToLocalTimeZone(rv.getDepartureDateTime(), tz));
		rv.setUpdated(TimezoneUtils.convertToLocalTimeZone(rv.getUpdated(), tz));
		rv.setCreated(TimezoneUtils.convertToLocalTimeZone(rv.getCreated(), tz));
		GuestProfileView gpv = rv.getGuestProfile();
		if (gpv != null) {
			gpv.setCreated(TimezoneUtils.convertToLocalTimeZone(gpv.getCreated(), tz));
			gpv.setUpdated(TimezoneUtils.convertToLocalTimeZone(gpv.getUpdated(), tz));
		}
		List<RateView> rvs = rv.getRates();
		if (rvs != null) {
			for (RateView rt : rvs) {
				rt.setFromDate(TimezoneUtils.convertToLocalTimeZone(rt.getFromDate(), tz));
				rt.setToDate(TimezoneUtils.convertToLocalTimeZone(rt.getToDate(), tz));
			}
		}
	}

	private void convRCViewToServerTime(RCView rv, MainEnums.TimeZone tz) {
		if (rv == null) {
			return;
		}
		rv.setGuestSignatureDateTime(TimezoneUtils.convertToServerTimeZone(rv.getGuestSignatureDateTime(), tz));
		rv.setArrivalDateTime(TimezoneUtils.convertToServerTimeZone(rv.getArrivalDateTime(), tz));
		rv.setDepartureDateTime(TimezoneUtils.convertToServerTimeZone(rv.getDepartureDateTime(), tz));
		List<RateView> rvs = rv.getRates();
		if (rvs != null) {
			for (RateView rt : rvs) {
				rt.setFromDate(TimezoneUtils.convertToServerTimeZone(rt.getFromDate(), tz));
				rt.setToDate(TimezoneUtils.convertToServerTimeZone(rt.getToDate(), tz));
			}
		}
	}

	private void convFolioViewToLocalTime(FolioView folio, MainEnums.TimeZone tz) {
		if (folio == null) {
			return;
		}
		folio.setGuestSignatureDateTime(TimezoneUtils.convertToLocalTimeZone(folio.getGuestSignatureDateTime(), tz));
		folio.setArrivalDateTime(TimezoneUtils.convertToLocalTimeZone(folio.getArrivalDateTime(), tz));
		folio.setDepartureDateTime(TimezoneUtils.convertToLocalTimeZone(folio.getDepartureDateTime(), tz));
		List<BillingView> bvs = folio.getBillings();
		if (bvs != null) {
			for (BillingView bv : bvs) {
				bv.setBillingDateTime(TimezoneUtils.convertToLocalTimeZone(bv.getBillingDateTime(), tz));
			}
		}
	}

	private void convMsgViewToLocalTime(List<MessageView> msgs, MainEnums.TimeZone tz) {
		if (msgs == null) {
			return;
		}
		for (MessageView mv : msgs) {
			mv.setMsgDateTime(TimezoneUtils.convertToLocalTimeZone(mv.getMsgDateTime(), tz));
		}
	}
}
